home *** CD-ROM | disk | FTP | other *** search
Text File | 1989-01-10 | 28.5 KB | 814 lines | [TEXT/EDIT] |
- ; Copyright (C) 1987 John Ulrich
- ; Permission to copy this software, in whole or in part, to use this
- ; software for any lawful purpose, and to redistribute this software
- ; is granted subject to the restriction that all copies made of this
- ; software must include this copyright notice in full.
- ; Neither John Ulrich nor Semantic Microsystems, Inc. make any warranty
- ; or representation of any kind concerning this software, either express
- ; or implied, including but not limited to implied warranties of
- ; merchantability or fitness for any particular purpose.
-
- (begin (set! include-source-code? #f)
- (set! include-lambda-list? #f)
- (set! include-procedure-name? #f))
-
- ; Variables assigned by this file
-
- (define describe)
- (define name->class)
- (define all-classvars)
- (define all-methods)
- (define class-compiled?)
- (define class-of-object)
- (define classvars)
- (define compile-class)
- (define define-class)
- (define define-method)
- (define delete-method)
- (define getcv)
- (define setcv)
- (define instvars)
- (define make-instance)
- (define methods)
- (define mixins)
- (define rename-class)
-
- (define send:
- (lambda x
- (let ((object (car x))(tail (cdr x)))
- (cond ((null? tail)
- (cerror "null message sent" object))
- (else
- (let* ((proc (car (->pair object)))
- (proc (if (procedure? proc)
- (proc (car tail))
- (cerror "bad argument to object" object))))
- (if (procedure? proc) (apply proc (cdr tail))
- (cerror "message not recieved" x))))))))
-
- (define dispatch
- (lambda (object msg)
- (let ((proc (car (->pair object))))
- (if (procedure? proc)
- (proc msg)
- (cerror "bad argument to object"
- object)))))
-
- (define send-if-handles:
- (lambda x
- (let ((object (car x))(tail (cdr x)))
- (cond ((null? tail)
- (cerror "null message sent" object))
- (else
- (let* ((proc (car (->pair object)))
- (proc (if (procedure? proc)
- (proc (car tail))
- (cerror "bad argument to object" object))))
- (if (procedure? proc) (apply proc (cdr tail))
- )))))))
-
-
- ;;; the following two macros are for compatibility
-
- (macro send (lambda (x)`(send: ,(cadr x) ',(caddr x) ,@(cdddr x))))
- (macro send-if-handles
- (lambda (x)
- `(send-if-handles: ,(cadr x) ',(caddr x) ,@(cdddr x))))
-
- ; Variables assigned temporarily and then made undefined.
- ; This was done to make it possible to compile this file
- ; on a one megabyte machine.
-
- (define *key*)
- (define inheritance)
- (define lookup-class)
- (define process-tail)
- (define process-option)
- (define instance-vars)
- (define class-vars)
- (define eqcar)
- (define attach-prefix)
- (define remdup)
- (define union)
- (define add-member)
- (define delete)
- (define set-value)
- (define get-value)
- (define locate)
- (define class-description)
- (define instance-description)
- (define class-list)
- (define class-list-set!)
-
- (let ((*class-list* '()))
- (set! class-list
- (lambda () *class-list*))
- (set! class-list-set!
- (lambda (x) (set! *class-list* x)))
- #t)
-
- (define *key* (gensym "key"))
-
- ;inheritance is a real time sink. Perhaps someone can think of a better
- ;way. For starters the name-space includes everything. We could break
- ;out name-space-vars name-space-methods which would reduce the work
- ;performed by member. However, I feel that some more basic changes
- ;could be made that would improve the efficiency
-
- (define inheritance
- (let ((*key* *key*))
- (define map-inheritance
- (let ()
- (define (map-inheritance1 mixins msg)
- (cond
- ((null? mixins) '())
- (else (append (map-inheritance (car mixins) msg)
- (map-inheritance1 (cdr mixins) msg)))))
- (lambda (class msg)
- (cons (cons class (send: (class *key*) msg))
- (map-inheritance1 (send (class *key*) get-mixins) msg)))))
- (define shadow
- (let ()
- (define filter
- (lambda (x fn)
- (cond
- ((null? x) '())
- ((fn (car x)) (filter (cdr x) fn))
- (else (cons (car x)(filter (cdr x) fn))))))
- (lambda (lst msg)
- (cond
- ((null? lst) '())
- (else
- (letrec
- ((name-space (send ((caar lst) *key*) get-name-space))
- (fn (if (member msg '(get-settable
- get-inittable get-gettable get-mixins))
- (lambda (x)(member x name-space))
- (lambda (x)(member (car x) name-space)))))
- (append (cdar lst)
- (filter (shadow (cdr lst) msg) fn))))))))
- (lambda (class msg)
- (shadow
- (map-inheritance class msg) msg))))
-
- (define lookup-class
- (let ((*key* *key*))
- (rec lookup-class
- (lambda (name cl)
- (cond
- ((null? cl) (cerror "illegal class name" name))
- ((eq? (send ((car cl) *key*) name) name) (car cl))
- (else (lookup-class name (cdr cl))))))))
-
- ;The efficiency here could be improved by caching functions
-
- (define process-option
- (let ((*key* *key*))
- (lambda (class option)
- (cond
- ((atom? option)
- (case option
- ((settable-variables)
- (for-each (dispatch (class *key*) 'add-settable)
- (mapcar car (append
- (send (class *key*) get-instvars)
- (send (class *key*) get-classvars)))))
- ((gettable-variables)
- (for-each (dispatch (class *key*) 'add-gettable)
- (mapcar car (append
- (send (class *key*) get-instvars)
- (send (class *key*) get-classvars)))))
- ((inittable-variables)
- (for-each (dispatch (class *key*) 'add-inittable)
- (mapcar car (append
- (send (class *key*) get-instvars)
- (send (class *key*) get-classvars)) )))))
- (else
- (case (car option)
- ((settable-variables)
- (for-each (dispatch (class *key*) 'add-settable)
- (cdr option)))
- ((gettable-variables)
- (for-each (dispatch (class *key*) 'add-gettable)
- (cdr option)))
- ((inittable-variables)
- (for-each (dispatch (class *key*) 'add-inittable)
- (cdr option)))))))))
-
- (define process-tail
- (let ((class-list class-list)
- (*key* *key*)
- (lookup-class lookup-class)
- (process-option process-option))
- (rec process-tail
- (lambda (class tail)
- (cond
- ((null? tail) class)
- (else
- (case (caar tail)
- ((classvars)
- (for-each (dispatch (class *key*) 'add-classvar)
- (cdar tail)))
- ((instvars)
- (for-each (dispatch (class *key*) 'add-instvar)
- (cdar tail)))
- ((methods)
- (for-each (dispatch (class *key*) 'add-method)
- (cdar tail)))
- ((mixins)
- (let ((fn (dispatch (class *key*) 'add-mixin)))
- (for-each (lambda (x) (fn (lookup-class x (class-list))))
- (cdar tail))))
- ((options)
- (for-each (lambda (x) (process-option class x))
- (cdar tail))))
- (process-tail class (cdr tail))))))))
-
- ;Helper functions
-
- (define instance-vars
- (let ((inheritance inheritance))
- (lambda (x)
- (inheritance x 'get-instvars))))
-
- (define class-vars
- (let ((inheritance inheritance))
- (lambda (x)
- (inheritance x 'get-classvars))))
-
- (define eqcar
- (lambda (x y) (eq? (car x) (car y))))
-
- (define attach-prefix
- (lambda (prefix symbol)
- (string->symbol (string-append prefix (symbol->string symbol)))))
-
- (define remdup)
- (define union)
-
- (let ()
- (define (member? x y test)
- (cond
- ((null? y) '())
- ((test x (car y)) #t)
- (else (member? x (cdr y) test))))
- (define (remdup1 y x equality)
- (cond
- ((null? x) (reverse y))
- ((member? (car x) y equality) (remdup1 y (cdr x) equality))
- (else (remdup1 (cons (car x) y) (cdr x) equality))))
- (set! remdup
- (lambda (x equality) (remdup1 '() x equality)))
- (set! union
- (rec union
- (lambda (x y equality)
- (cond
- ((null? x) y)
- ((member? (car x) y equality) (union (cdr x) y equality))
- (else (cons (car x) (union (cdr x) y equality))))))))
-
- (define add-member
- (lambda (x y . fn)
- ((if (null? fn)
- (rec loop (lambda (z)
- (cond
- ((null? z) (list x))
- ((eq? x (car z)) (cons x (cdr z)))
- (else (cons (car z) (loop (cdr z)))))))
- (let* ((fn (car fn)) (name (fn x)))
- (rec loop (lambda (z)
- (cond
- ((null? z) (list x))
- ((eq? name (fn (car z)))
- (cons x (cdr z)))
- (else (cons (car z) (loop (cdr z))))))))) y)))
-
- (define delete
- (rec delete
- (lambda (x y test)
- (cond
- ((null? y) '())
- ((test x (car y)) (cdr y))
- (else (cons (car y) (delete x (cdr y) test)))))))
-
- (define set-value
- (lambda (env loc value)
- (vector-set! (car env) loc value)
- value))
-
- (define get-value
- (lambda (env loc)
- (vector-ref (car env) loc)))
-
- (define locate
- (letrec ((locate1
- (lambda (x y n)
- (cond
- ((null? y)
- (cerror
- "tried to locate a non-existant variable in environment"))
- ((eq? x (caar y)) n)
- (else (locate1 x (cdr y) (1+ n)))))))
- (lambda (x y)
- (locate1 x y 0))))
-
- (define class-description
- (let ((*key* *key*)
- (inheritance inheritance)
- (writeln (lambda l (for-each display l) (newline))))
- (lambda (class)
- (writeln " ")
- (writeln " CLASS DESCRIPTION ")
- (writeln " ================== ")
- (writeln " ")
- (writeln " NAME : " (send (class *key*) name))
- (writeln " CLASS VARS : "
- (mapcar car (inheritance class 'get-classvars )))
- (writeln " INSTANCE VARS : "
- (mapcar car (inheritance class 'get-instvars )))
- (writeln " METHODS : "
- (mapcar car (inheritance class 'get-methods)))
- (writeln " MIXINS : "
- (mapcar (lambda (x)
- (send (x *key*) name))
- (inheritance class 'get-mixins)))
- (writeln " CLASS COMPILED : "
- (not (null? (send (class *key*) compiled?))))
-
- (writeln " CLASS INHERITED : "
- (mapcar (lambda (x) (send (x *key*) name))
- (send (class *key*) get-subclasses)))
- (string->symbol ""))))
-
- (define instance-description
- (let ((*key* *key*)
- (inheritance inheritance)
- (writeln (lambda l (for-each display l) (newline))))
- (lambda (inst)
- (letrec ((class (send inst get-class))
- (printvars
- (lambda (f1 f2) ;f1 is a list of instvars and f2 an environment
- (let ((n 0))
- (while f1
- (writeln " " (car f1) " : " (vector-ref f2 n))
- (set! n (1+ n))
- (set! f1 (cdr f1)))))))
-
- (writeln " ")
- (writeln " INSTANCE DESCRIPTION ")
- (writeln " ==================== ")
- (writeln " ")
- (writeln " Instance of Class " (send (class *key*) name))
- (writeln " ")
- (writeln " Class Variables : ")
- (printvars (mapcar car (inheritance class 'get-classvars ))
- (car(send (class *key*) get-class-environment)))
- (writeln " ")
- (writeln "Instance Variables :")
- (printvars (mapcar car (inheritance class 'get-instvars))
- (cadr (->pair (car (->pair inst)))))
- (string->symbol "")
- ))))
-
-
- ;;; this is the beginning of the main lexical environment of SCOOPS
-
- (let ((key *key*)
- (inheritance inheritance)
- (lookup-class lookup-class)
- (process-tail process-tail)
- (process-option process-option)
- (instance-vars instance-vars)
- (class-vars class-vars)
- (eqcar eqcar)
- (attach-prefix attach-prefix)
- (remdup remdup)
- (union union)
- (add-member add-member)
- (delete delete)
- (set-value set-value)
- (get-value get-value)
- (locate locate)
- (class-description class-description)
- (instance-description instance-description)
- (class-list class-list)
- (class-list-set! class-list-set!))
-
- (define *key* key) ; the key for classes in this environment
-
- ;this monster is the framework for creating classes. Obviously
- ;improvement in speed could be made by using records instead of
- ;lexical environments. However, we should see what the dispatching
- ;overhead is before making such a change. I have used a key in the
- ;following definition so that foreign code cannot send messages directly
- ;to classes.
-
- (define make-class
- (lambda (name)
- (letrec
- ((classvars '())
- (instvars '())
- (mixins '())
- (gettable '())
- (settable '())
- (inittable '())
- (methods '())
- (make-fn '())
- (subclasses '())
- (all-classvars '())
- (all-settable '())
- (all-gettable '())
- (self
- (lambda x
- (if (and x (eq? (car x) *key*))
- (->symbol
- (list
- (lambda (msg)
- (case msg
-
- ;we put make-instance first to minimize dispatching time
- ((make-instance)
- (if (null? make-fn)
- (set! make-fn
- (eval (compile-make-fn self)
- class-environment)))
- (lambda x (apply make-fn x)))
- ((getcv)
- (lambda (x)
- (if (member x all-gettable)
- (get-value class-environment
- (locate x all-classvars))
- (cerror "variable not gettable" x))))
- ((setcv)
- (lambda (x y)
- (if (member x all-settable)
- (set-value class-environment
- (locate x all-classvars)
- y)
- (cerror "variable not settable" x))))
- ((name) (lambda () name))
- ((set-name) (lambda (x)(set! name x)))
- ((get-subclasses) (lambda () subclasses))
- ((add-subclass)
- (lambda (x)
- (set! subclasses
- (add-member x
- subclasses
- (lambda (x)
- (send (x *key*) name))))))
- ((remove-subclass)
- (lambda (x)
- (set! subclasses (remove x subclasses))))
-
- ((get-methods) (lambda () methods))
- ((delete-method)
- (lambda (x)
- (set! methods (delete x methods eqcar))
- (send self nil-make-fn)))
- ((nil-make-fn)
- (lambda ()
- (set! make-fn '())
- (mapcar (lambda (x)
- (send (x *key*) nil-make-fn))
- subclasses)))
- ((add-method)
- (lambda (x)
- (send (self *key*) nil-make-fn)
- (set! methods (add-member x methods car))))
- ((add-classvar)
- (lambda (x)
- (set! classvars
- (add-member (if (atom? x)
- (cons x '())
- (cons (car x) (cadr x)))
- classvars
- car))))
-
- ((set-all-classvars)
- (lambda (x) (set! all-classvars x)))
- ((get-classvars) (lambda () classvars))
- ((get-all-classvars) (lambda () all-classvars))
- ((add-instvar)
- (lambda (x)
- (set! instvars
- (add-member (if (atom? x)
- (cons x '())
- (cons (car x)(cadr x)))
- instvars
- car))))
- ((get-instvars) (lambda () instvars))
- ((add-mixin)
- (lambda (x)
- (send (x *key*) add-subclass self)
- (set! mixins (add-member x mixins ))))
- ((get-all-instvars)
- (inheritance self 'get-instvars eqcar))
- ((get-mixins) (lambda () mixins))
- ((get-inittable) (lambda () inittable))
-
- ((add-inittable)
- (lambda (x)
- (set! make-fn '())
- (set! inittable
- (add-member x inittable))))
- ((get-settable) (lambda () settable))
- ((add-settable)
- (lambda (x)
- (set! make-fn '())
- (set! settable (add-member x settable ))))
- ((set-all-settable)
- (lambda (x)(set! all-settable x)))
- ((get-gettable) (lambda () gettable))
- ((add-gettable)
- (lambda (x)
- (set! make-fn '())
- (set! gettable (add-member x gettable))))
- ((set-all-gettable)
- (lambda (x) (set! all-gettable x)))
- ((compiled?) (lambda () make-fn))
- ((compile)
- (lambda ()
- (set! make-fn
- (eval (compile-make-fn self)
- class-environment))
- ))
- ((get-name-space)
- (lambda ()
- (append mixins
- (mapcar car
- (append classvars
- instvars
- methods)))))
- ((set-make-fn)
- (lambda (fn)
- (set! class-environment
- (cdr (->pair fn)))
- (set! make-fn fn)))
- ((get-make-fn)
- (lambda () (compile-make-fn self)))
- ((get-class-environment)
- (lambda () class-environment))
- ))
- (cons 'pname
- (string-append "class:"
- (symbol->string name)))))
- (cerror "private object, key required" self)
- ))))
- self)))
-
- (define define-class-fn
- (lambda x
- (let ((class (process-tail (make-class (car x)) (cdr x))))
- (class-list-set!
- (add-member class
- (class-list)
- (lambda (x) (send (x *key*) name))))
-
- ;the following list need to be cached to support getcv and setcv
- (send (class *key*)
- set-all-classvars
- (inheritance class 'get-classvars))
- (send (class *key*)
- set-all-gettable
- (inheritance class 'get-gettable))
- (send (class *key*)
- set-all-settable
- (inheritance class 'get-settable))
- (send (class *key*) nil-make-fn)
- class)))
-
- (define compile-make-fn
- (lambda (x)
- (let* ((params (gensym "init-parms"))
- (instvars (instance-vars x))
- (totalvars (append instvars (class-vars x))))
- `(lambda
- ,params
- (letrec
- ,(append
- (format-vars instvars)
- (list
- (list 'self
- `(lambda
- msg
- (case (car msg)
- ,@(format-case
- (append
- `((get-class (lambda (),x)))
- (get-methods (inheritance x 'get-gettable)
- totalvars)
- (set-methods (inheritance x 'get-settable)
- totalvars)
- (inheritance x 'get-methods)
- )))))))
- ,(compile-init-code x params)
- (->symbol
- (list self
- ',(cons 'pname
- (string-append "instance:"
- (symbol->string
- (send (x *key*) name)))))))))))
-
-
-
- (define compile-init-code
- (lambda (x init-params)
- `(while ,init-params
- (cond
- ,@(condition-actions (inheritance x 'get-inittable)
- init-params)
- (else (error "variable not inittable"
- (car ,init-params))))
- (set! ,init-params (cddr ,init-params)))))
-
- (define condition-actions
- (lambda (vars init-params)
- (mapcar (lambda (x)
- `((eq? (car ,init-params) ',x)
- (set! ,x (cadr ,init-params))))
- vars)))
-
- (define compile-class-environment
- (lambda (x)
- (letrec ((var (send x get-classvars))
- (env (make-vector (1+ (length var)) '())))
- (vector-set! env (length var) (mapcar (lambda (x) (car x)) var))
- (list env))))
-
- (define format-case
- (lambda (x)
- (append (mapcar (lambda (y) (cons (list (car y)) (cdr y)))
- x)
- '((else (if (cdr msg) ((cadr msg)) '#f))))))
-
- (define format-vars
- (lambda (all-vars)
- (mapcar (lambda (y) (list (car y) (unwindinitval (cdr y))))
- all-vars)))
-
- (define unwindinitval
- (lambda (y)
- (cond
- ((and (pair? y) (eq? (car y) 'active))
- (unwindinitval (cadr y)))
- (else y))))
-
-
- (define get-methods
- (lambda (lst all-vars)
- (mapcar (lambda (x) ;x = var
- (let ((y (assq x all-vars)))
- ; y = (x . form) | (x . (active form getfn setfn))
- (if (null? y)
- (cerror "cannot make get-var function for" x)
- (list (attach-prefix "get-" x)
- `(lambda () ,(unwindgetfn x (cdr y)))))))lst)))
-
- (define unwindgetfn
- (lambda (var vardefn)
- (cond
- ((and (pair? vardefn) (eq? (car vardefn) 'active))
- (list (caddr vardefn) (unwindgetfn var (cadr vardefn))))
- (else var))))
-
-
-
- (define set-methods
- (let ((*a1* (gensym)))
- (lambda (lst all-vars)
- (mapcar (lambda (x)
- (let ((y (assq x all-vars)))
- (if (null? y)
- (cerror "cannot make set-var function for " x)
- (list (attach-prefix "set-" x)
- `(lambda (,*a1*)
- (set! ,x
- ,(unwindsetfn *a1*
- (cdr y))))))))
- lst))))
-
-
-
- (define unwindsetfn
- (lambda (parm vardefn)
- (cond
- ((and (pair? vardefn) (eq? (car vardefn) 'active))
- (list (cadddr vardefn) (unwindsetfn parm (cadr vardefn))))
- (else parm))))
-
- ;;;exports
-
- (set! describe
- (lambda (class-inst)
- (if (member class-inst (class-list))
- (class-description class-inst)
- (instance-description class-inst))))
-
-
- (set! name->class
- (lambda (x)(lookup-class x (class-list))))
-
-
- ;the following may as well use the cached all-classvars
- (set! all-classvars
- (lambda (obj) (mapcar car (send (obj *key*) get-all-classvars))))
-
- (set! all-instvars
- (lambda (obj) (mapcar car (inheritance obj 'get-instvars))))
-
-
- (set! all-methods
- (lambda (obj) (inheritance obj 'get-methods )))
-
- (set! class-compiled?
- (lambda (obj) (if (send (obj *key*) compiled?) #t #f)))
-
- (set! class-of-object
- (lambda (obj) (send ((send obj get-class) *key*) name)))
-
- (set! classvars
- (lambda (obj) (mapcar car (send (obj *key*) get-classvars))))
-
- (set! compile-class
- (lambda (obj) (send (obj *key*) compile)))
-
- (macro define-class
- (lambda (x)
- (let* ((new-class (apply define-class-fn (cdr x)))
- ;(foo (display (list 'env (send (location *key*)
- ; get-class-environment))))
- (class-vars (format-vars (send (new-class *key*)
- get-all-classvars)))
- (code (compile-make-fn new-class))
- (name (send (new-class *key*) name)))
- `(begin
- (set! ,name ,new-class)
- (send (,new-class ',*key*) set-make-fn
- (let ,class-vars
- ,code))))))
-
-
- (macro define-method
- (lambda (x) ; x = (define-method (class method) (...args...) body)
- `(send (,(caadr x) ',*key*)
- add-method
- ',(list (cadadr x) `(lambda ,(caddr x) ,(cadddr x))))))
- (macro delete-method
- (lambda (x) ; x = (delete-method (class method))
- `(send (,(name->class (caadr x)) ',*key*)
- delete-method
- (cadadr x))))
-
-
- (macro getcv
- (lambda (x) ; x = (getcv obj var)
- `(send (,(cadr x) ',*key*) getcv ',(caddr x))))
-
- (macro setcv
- (lambda (x) ; x = (setcv obj var newval)
- `(send (,(cadr x) ',*key*) setcv ',(caddr x) ,(cadddr x))))
-
- (set! instvars
- (lambda (obj)(send (obj *key*) get-instvars)))
-
- (macro make-instance
- (lambda (x) ; x = (make-instance class var val var val ... )
- `(send (,(cadr x) ',*key*) make-instance ,@(cddr x))))
-
- (set! methods
- (lambda (obj) (send (obj *key*) get-methods)))
-
- (set! mixins
- (lambda (obj)(mapcar (lambda (x)(send (x *key*) name))
- (send (obj *key*) get-mixins))))
-
- (macro rename-class (lambda (x) ; x = (rename-class (class newname))
- `(send (,(caadr x) ',*key*) set-name ',(cadadr x))))
-
-
- )
-
- (define *key*)
- (define inheritance)
- (define lookup-class)
- (define process-tail)
- (define process-option)
- (define instance-vars)
- (define class-vars)
- (define eqcar)
- (define attach-prefix)
- (define remdup)
- (define union)
- (define add-member)
- (define delete)
- (define set-value)
- (define get-value)
- (define locate)
- (define class-description)
- (define instance-description)
- (define class-list)
- (define class-list-set!)
-
- (begin (set! include-source-code? #t)
- (set! include-lambda-list? #t)
- (set! include-procedure-name? #t))